home *** CD-ROM | disk | FTP | other *** search
- unit PetrVones.Utils.DataPacket;
-
- interface
-
- uses
- System.Data, System.IO, System.Text, System.Xml;
-
- type
- EDataPacketError = class(System.Data.DataException);
-
- procedure FillDataSet(DS: DataSet; DatPacketReader: TextReader); overload;
- procedure FillDataSet(DS: DataSet; DatPacket: string); overload;
-
- implementation
-
- resourcestring
- RsElelementNotFound = 'Expected element {0} not found';
- RsInvalidFieldType = 'Invalid field type "{0}"';
-
- type
- TDataPacketElement = (peDataPacket, peMetadata, peFields, peField, peRowData);
- TDataPacketConversion = (coNone, coDate, coDateTime, coTime, coBoolean);
-
- const
- DataPacketElementNames: array [TDataPacketElement] of string = ('DATAPACKET', 'METADATA', 'FIELDS', 'FIELD', 'ROWDATA');
-
- type
- TDataPacketDataColumn = class(DataColumn)
- private
- FDataPacketConversion: TDataPacketConversion;
- protected
- property DataPacketConversion: TDataPacketConversion read FDataPacketConversion write FDataPacketConversion;
- end;
-
- type
- TDataPacketXmlReader = class(XmlTextReader)
- private
- FCurrentTable: DataTable;
- FDescription: DataSet;
- public
- function get_Value: string; override;
- function Read: Boolean; override;
- property Description: DataSet read FDescription write FDescription;
- end;
-
- { TDataPacketXmlReader }
-
- function TDataPacketXmlReader.get_Value: string;
- var
- Column: TDataPacketDataColumn;
- begin
- Result := inherited get_Value;
- case NodeType of
- XmlNodeType.Attribute:
- begin
- if Assigned(FCurrentTable) then
- Column := TDataPacketDataColumn(FCurrentTable.Columns[Name])
- else
- Column := nil;
- if Assigned(Column) and (Column.ColumnMapping <> MappingType.Hidden) then
- case Column.DataPacketConversion of
- coTime:
- Insert('.', Result, 9);
- coDate, coDateTime:
- if (Result.Length = 20) and (Result[9] = 'T') and (Result[12] = ':') then
- begin
- Insert('-', Result, 5);
- Insert('-', Result, 8);
- Delete(Result, 20, 3);
- end
- else
- if Result.Length = 8 then
- begin
- Insert('-', Result, 5);
- Insert('-', Result, 8);
- end;
- coBoolean:
- Result := Result.ToLower;
- end;
- end;
- end;
- end;
-
- function TDataPacketXmlReader.Read: Boolean;
- begin
- Result := inherited Read;
- if Result and (NodeType = XmlNodeType.Element) and HasAttributes then
- FCurrentTable := Description.Tables[Name];
- end;
-
- { FillDataSet }
-
- procedure LoadDataPacket(DS: DataSet; Reader: XmlReader);
- const
- RootTableName = 'ROW';
- var
- ElementName: string;
- ExpectingElement: TDataPacketElement;
-
- procedure CheckElementName(Element: TDataPacketElement);
- begin
- if DataPacketElementNames[Element] <> ElementName then
- raise EDataPacketError.Create(System.String.Format(RsElelementNotFound, [ElementName]));
- end;
-
- function CreateIdColumn(Table, NameTable: DataTable): DataColumn;
- var
- IdColumnName: string;
- begin
- IdColumnName := NameTable.TableName + '_IdNestedRel';
- Result := Table.Columns[IdColumnName];
- if not Assigned(Result) then
- begin
- Result := Table.Columns.Add(IdColumnName);
- Result.DataType := typeof(System.Int32);
- Result.ColumnMapping := MappingType.Hidden;
- end;
- end;
-
- procedure InvalidFieldType(FieldType: string);
- begin
- raise EDataPacketError.Create(System.String.Format(RsInvalidFieldType, [FieldType]));
- end;
-
- procedure ReadFields(CurrentTable: DataTable);
- type
- TDataColumn_Array = array of DataColumn;
- var
- AttrName, AttrNameValue, FieldTypeValue, SubTypeValue: string;
- Column: TDataPacketDataColumn;
- ParentIdColumn, ChildIdColumn: DataColumn;
- NestedTable: DataTable;
- NestedRelation: DataRelation;
- RelationName: string;
- begin
- while Reader.Read do
- case Reader.NodeType of
- XmlNodeType.Element:
- if Reader.Name = DataPacketElementNames[peField] then
- begin
- AttrName := '';
- FieldTypeValue := '';
- SubTypeValue := '';
- while Reader.MoveToNextAttribute do
- begin
- AttrName := Reader.Name.ToLower;
- if AttrName = 'attrname' then
- AttrNameValue := Reader.Value
- else
- if AttrName = 'fieldtype' then
- FieldTypeValue := Reader.Value
- else
- if AttrName = 'subtype' then
- SubTypeValue := Reader.Value;
- end;
- if FieldTypeValue = 'nested' then
- begin
- ParentIdColumn := CreateIdColumn(CurrentTable, CurrentTable);
- ParentIdColumn.AllowDBNull := False;
- ParentIdColumn.AutoIncrement := True;
- ParentIdColumn.Unique := True;
- CurrentTable.PrimaryKey := TDataColumn_Array.Create(ParentIdColumn);
- NestedTable := DS.Tables.Add(CurrentTable.TableName + AttrNameValue);
- ChildIdColumn := CreateIdColumn(NestedTable, CurrentTable);
- RelationName := CurrentTable.TableName + '_' + NestedTable.TableName;
- NestedRelation := DS.Relations.Add(RelationName, ParentIdColumn, ChildIdColumn, True);
- NestedRelation.Nested := True;
- ReadFields(NestedTable);
- end
- else
- begin
- Column := TDataPacketDataColumn.Create;
- Column.DataPacketConversion := coNone;
- Column.ColumnName := AttrNameValue;
- Column.ColumnMapping := MappingType.Attribute;
- Column.Caption := AttrNameValue;
- if FieldTypeValue = 'fixed' then
- Column.DataType := typeof(System.Decimal)
- else
- if FieldTypeValue = 'boolean' then
- begin
- Column.DataType := typeof(System.Boolean);
- Column.DataPacketConversion := coBoolean;
- end
- else
- if FieldTypeValue = 'r8' then
- Column.DataType := typeof(System.Double)
- else
- if FieldTypeValue = 'date' then
- begin
- Column.DataType := typeof(System.DateTime);
- Column.DataPacketConversion := coDate;
- end
- else
- if FieldTypeValue = 'dateTime' then
- begin
- Column.DataType := typeof(System.DateTime);
- Column.DataPacketConversion := coDateTime;
- end
- else
- if FieldTypeValue = 'i4' then
- Column.DataType := typeof(System.Int32)
- else
- if FieldTypeValue = 'i8' then
- Column.DataType := typeof(System.Int64)
- else
- if FieldTypeValue = 'i2' then
- Column.DataType := typeof(System.Int16)
- else
- if FieldTypeValue = 'string' then
- Column.DataType := typeof(System.String)
- else
- if FieldTypeValue = 'time' then
- begin
- Column.DataType := typeof(System.DateTime);
- Column.DataPacketConversion := coTime;
- end
- else
- if FieldTypeValue = 'string.uni' then
- Column.DataType := typeof(System.String)
- else
- if FieldTypeValue = 'ui2' then
- Column.DataType := typeof(System.UInt16)
- else
- if FieldTypeValue = 'ui4' then
- Column.DataType := typeof(System.UInt32)
- else
- if FieldTypeValue = 'bin.hex' then
- begin
- if SubTypeValue = 'Text' then
- Column.DataType := typeof(System.String)
- else
- if (SubTypeValue = 'Graphics') or (SubTypeValue = 'TypedBinary') then
- Column.DataType := typeof(TBytes)
- else
- InvalidFieldType(System.String.Format('{0}/{1}', [FieldTypeValue, SubTypeValue]));
- end
- else
- InvalidFieldType(FieldTypeValue);
- CurrentTable.Columns.Add(Column);
- end;
- end;
- XmlNodeType.EndElement:
- if Reader.Name = DataPacketElementNames[peFields] then
- Break;
- end;
- end;
-
- procedure ReadData;
- begin
- DS.ReadXml(Reader, XmlReadMode.IgnoreSchema);
- end;
-
- begin
- ExpectingElement := peDataPacket;
- while Reader.Read do
- case Reader.NodeType of
- XmlNodeType.Element:
- begin
- ElementName := Reader.Name;
- case ExpectingElement of
- peDataPacket:
- begin
- CheckElementName(peDataPacket);
- ExpectingElement := peMetadata;
- end;
- peMetadata:
- begin
- CheckElementName(peMetadata);
- ExpectingElement := peFields;
- end;
- peFields:
- begin
- ReadFields(DS.Tables.Add(RootTableName));
- ExpectingElement := peRowData;
- Reader.Skip;
- end;
- peRowData:
- if ElementName = DataPacketElementNames[peRowData] then
- begin
- ReadData;
- Break;
- end;
- end;
- end;
- end;
- end;
-
- procedure FillDataSet(DS: DataSet; DatPacketReader: TextReader);
- var
- Reader: TDataPacketXmlReader;
- begin
- DS.Reset;
- Reader := TDataPacketXmlReader.Create(DatPacketReader);
- try
- Reader.Description := DS;
- LoadDataPacket(DS, Reader);
- finally
- Reader.Close;
- end;
- end;
-
- procedure FillDataSet(DS: DataSet; DatPacket: string);
- var
- Reader: StringReader;
- begin
- Reader := StringReader.Create(DatPacket);
- try
- FillDataSet(DS, Reader);
- finally
- Reader.Close;
- end;
- end;
-
- end.
-